#include "util_texshader.h"

//---------------------CONSTRUCTORS / DESTRUCTORS--------------------------------------------------------------
/******************************************
* Constructor for initialising the member
* variables of the texture shader.  In this
* case, we set all the pointers to zero.
******************************************/
LJMUUtilShaderTexPlain::LJMUUtilShaderTexPlain()
{
	this->_obj_effect		= NULL;
	this->_obj_technique	= NULL;
	this->_obj_layout		= NULL;
	this->_obj_device		= NULL;
	this->_ptr_mat_world	= NULL;
	this->_ptr_mat_view		= NULL;
	this->_ptr_mat_proj		= NULL;
	this->_ptr_tex_res		= NULL;
}

//--------------------PUBLIC METHODS-----------------------------------------------------------------------------

/******************************************
* Initialise the Shader object and return
* the success as either true or false.
******************************************/
bool LJMUUtilShaderTexPlain::initialise(ID3D10Device* pdevice,std::wstring pshaderlocation)
{
	if(pdevice != NULL)
	{
		HRESULT						tresult;
		ID3D10Blob*					terrormsg;
		D3D10_INPUT_ELEMENT_DESC	tarrpolylayout[2];
		unsigned int				telementcount;
	    D3D10_PASS_DESC				tpassdesc;
	
		this->_prop_shaderloc = pshaderlocation;
		this->_obj_device	  = pdevice;

		// Load the shader in from the file - we are using Shader Model 4.0 for this shader.
		tresult = D3DX10CreateEffectFromFile(this->_prop_shaderloc.c_str(), NULL, NULL, "fx_4_0", D3D10_SHADER_ENABLE_STRICTNESS, 0,this->_obj_device, NULL, NULL, &_obj_effect, &terrormsg, NULL);
		if(FAILED(tresult))
			return false;

		// Get a pointer to the technique inside the shader.
		_obj_technique = _obj_effect->GetTechniqueByName("TextureTechnique");
		if(!_obj_technique)
			return false;
	
		// Now setup the layout of the data that goes into the shader.
		// This setup needs to match the VertexType stucture in the Bitmap Class and in the shader file itself.
		tarrpolylayout[0].SemanticName			= "POSITION";
		tarrpolylayout[0].SemanticIndex			= 0;
		tarrpolylayout[0].Format				= DXGI_FORMAT_R32G32B32_FLOAT;
		tarrpolylayout[0].InputSlot				= 0;
		tarrpolylayout[0].AlignedByteOffset		= 0;
		tarrpolylayout[0].InputSlotClass		= D3D10_INPUT_PER_VERTEX_DATA;
		tarrpolylayout[0].InstanceDataStepRate	= 0;

		tarrpolylayout[1].SemanticName			= "TEXCOORD";
		tarrpolylayout[1].SemanticIndex			= 0;
		tarrpolylayout[1].Format				= DXGI_FORMAT_R32G32_FLOAT;
		tarrpolylayout[1].InputSlot				= 0;
		tarrpolylayout[1].AlignedByteOffset		= D3D10_APPEND_ALIGNED_ELEMENT;
		tarrpolylayout[1].InputSlotClass		= D3D10_INPUT_PER_VERTEX_DATA;
		tarrpolylayout[1].InstanceDataStepRate	= 0;

		// Get a count of the elements in the layout.
		telementcount = sizeof(tarrpolylayout) / sizeof(tarrpolylayout[0]);

		// Get the description of the first pass described in the shader technique.
		_obj_technique->GetPassByIndex(0)->GetDesc(&tpassdesc);

		// Create the input layout.
		tresult = pdevice->CreateInputLayout(tarrpolylayout, telementcount, tpassdesc.pIAInputSignature, tpassdesc.IAInputSignatureSize, &_obj_layout);
		if(FAILED(tresult))
			return false;

		// Get pointers to the three matrices inside the shader so we can update them from this class.
		_ptr_mat_world = _obj_effect->GetVariableByName("worldMatrix")->AsMatrix();
		_ptr_mat_view =	 _obj_effect->GetVariableByName("viewMatrix")->AsMatrix();
		_ptr_mat_proj =	 _obj_effect->GetVariableByName("projectionMatrix")->AsMatrix();

		// Get pointer to the texture resource inside the shader.
		_ptr_tex_res =	_obj_effect->GetVariableByName("shaderTexture")->AsShaderResource();
		return true;
	}
	return false;
}

/******************************************
*
******************************************/
void LJMUUtilShaderTexPlain::cleanup()
{
	// Release the pointer to the texture in the shader file.
	_ptr_tex_res = NULL;

	// Release the pointers to the matrices inside the shader.
	_ptr_mat_world = NULL;
	_ptr_mat_view  = NULL;
	_ptr_mat_proj  = NULL;

	// Release the pointer to the shader layout.
	if(_obj_layout)
	{
		_obj_layout->Release();
		_obj_layout = NULL;
	}

	// Release the pointer to the shader technique.
	_obj_technique = NULL;

	// Release the pointer to the shader.
	if(_obj_effect)
	{
		_obj_effect->Release();
		_obj_effect = NULL;
	}
}

/******************************************
*
*
******************************************/
void LJMUUtilShaderTexPlain::render(int pindexcount, D3DXMATRIX pmatworld, D3DXMATRIX pmatview, D3DXMATRIX pmatprojection, ID3D10ShaderResourceView* ptexres)
{
	// Set the shader parameters that it will use for rendering.
	internSetShaderParams(pmatworld, pmatview, pmatprojection, ptexres);
	// Now render the prepared buffers with the shader.
	internRenderShader(pindexcount);
	return;
}

/******************************************
*
******************************************/
void LJMUUtilShaderTexPlain::internSetShaderParams(D3DXMATRIX pmatworld, D3DXMATRIX pmatview, D3DXMATRIX pprojmatrix, ID3D10ShaderResourceView* ptexres)
{
	// Set the world matrix variable inside the shader.
    _ptr_mat_world->SetMatrix((float*)&pmatworld);
	// Set the view matrix variable inside the shader.
	_ptr_mat_view->SetMatrix((float*)&pmatview);
	// Set the projection matrix variable inside the shader.
    _ptr_mat_proj->SetMatrix((float*)&pprojmatrix);
	// Bind the texture.
	_ptr_tex_res->SetResource(ptexres);
	return;
}

/******************************************
*
******************************************/
void LJMUUtilShaderTexPlain::internRenderShader(int pindexcount)
{
    D3D10_TECHNIQUE_DESC tdx_tech_desc;
	unsigned int i;
	
	// Set the input layout.
	this->_obj_device->IASetInputLayout(_obj_layout);

	// Get the description structure of the technique from inside the shader so it can be used for rendering.
    _obj_technique->GetDesc(&tdx_tech_desc);

    // Go through each pass in the technique (should be just one currently) and render the triangles.
	for(i=0; i<tdx_tech_desc.Passes; ++i)
    {
        _obj_technique->GetPassByIndex(i)->Apply(0);
		this->_obj_device->DrawIndexed(pindexcount, 0, 0);
    }
	return;
}